package com.xzy.sms.client;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.xzy.sms.entity.ContentSms;
import com.xzy.sms.entity.TemplateSms;
import com.xzy.sms.exception.SendSmsException;
import com.xzy.sms.utils.SmsUtils;

/**
 * @desc 短信发送实例
 * @author wjw
 * @time 2017年11月16日下午2:36:14
 */
public class SmsClient {
    
    /** FIXME */
    private Logger logger = Logger.getLogger(SmsClient.class.getName());

    /** 短信发送的地址 */
    private String url;
    /** 应用ID */
    private String appId;
    /** 密钥 */
    private String secretKey;
    /** 模板code */
    private String templateCode;
    
    /** FIXME */
    private OkHttpClient client = null;
    
    /** FIXME */
    private static final Pattern RESULT_PATTERN = Pattern.compile("^\\s*\\{\\s*\"state\"\\s*:\\s*(\\d+)\\s*,\\s*\"message\"\\s*:\\s*\"([^\"]*)\"",
        Pattern.MULTILINE);
    private static final String charset = "0123456789";// 随机因子
	private static final int codelen = 6;
        
    /**
     * 构造函数
     * @param url x
     * @param appId x
     * @param secretKey x
     */
    public SmsClient(String url, String appId, String secretKey, String templateCode) {
        this.url = url;
        this.appId = appId;
        this.secretKey = secretKey;
        this.templateCode=templateCode;
        builderClient();
    }
    
    /**
     * FIXME 方法注释信息(此标记由Eclipse自动生成,请填写注释信息删除此标记)
     */
    private void builderClient() {
        client = new OkHttpClient();
        client.setConnectTimeout(30, TimeUnit.SECONDS);
        client.setReadTimeout(60, TimeUnit.SECONDS);
        client.setWriteTimeout(60, TimeUnit.SECONDS);
    }
    
    public String getUrl() {
        return url;
    }
    public String getAppId() {
        return appId;
    }
    public String getSecretKey() {
        return secretKey;
    }
	public String getTemplateCode() {
		return templateCode;
	}

	/**
     * 通过基础信息内容发送短信
     * @param sms xx
     * @throws SendSmsException xx
     */
    public void sendSms(ContentSms sms) throws SendSmsException {
        if (sms == null || SmsUtils.isEmpty(sms.getContent()) || SmsUtils.isEmpty(sms.getMobile())) {
            throw new NullPointerException("参数mobile,content不能为null");
        }
        RequestBody requestBody = getRequestMap(sms);
        processResult(requestBody);
    }
    
    /**
     * 通过模板发送短信
     * @param sms xx
     * @throws SendSmsException xx
     */
    public void sendSms(TemplateSms sms) throws SendSmsException {
        if (sms == null || SmsUtils.isEmpty(sms.getMobile()) || (SmsUtils.isEmpty(sms.getTemplateCode()) && SmsUtils.isEmpty(sms.getTemplateId()))) {
            throw new NullPointerException("参数mobile,和(templateCode或者templateId)不能为null");
        }
        RequestBody requestBody = getRequestMap(sms);
        processResult(requestBody);
    }
    
    /**
     * 发送短信请求
     * @param requestBody
     * @throws SendSmsException
     */
    private void processResult(RequestBody requestBody) throws SendSmsException {
        logger.log(Level.INFO, requestBody.toString());
        Request req = new Request.Builder().url(url).header("User-Agent", "SmsClinet-SDK").post(requestBody).build();
        
        // .header("User-Agent", "SmsClient-SDK")
        try {
            client = new OkHttpClient();
            Response res = client.newCall(req).execute();
            if (res.isSuccessful()) {
                String body = res.body().string();
                // 对结果进行解析
                RestResult result = parseResult(body);
                logger.log(Level.FINE, "发送结果：" + body);
                if (result == null) {
                    throw new SendSmsException("意外的结果:" + body);
                } else if (result.getState() != 0) {
                    throw new SendSmsException("发送短信失败:" + result.getMessage());
                }
            } else {
                String body = res.body().string();
                logger.log(Level.INFO, "发送结果：" + body);
                throw new SendSmsException("发送短信失败(" + res.code() + ")");
            }
        } catch (IOException e) {
            throw new SendSmsException(e);
        }
    }
    
    /**
     * 对结果进行解析
     * @param content
     * @return
     */
    private RestResult parseResult(String content) {
        RestResult result = null;
        Matcher matcher = RESULT_PATTERN.matcher(content);
        if (matcher.find()) {
            result = new RestResult();
            result.setState(Integer.parseInt(matcher.group(1)));
            result.setMessage(matcher.group(2));
        }
        return result;
    }
    
    /**
     * 包装请求基本为RequestBody对象
     * @param sms
     * @return
     */
    private RequestBody getRequestMap(ContentSms sms) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("mobile", sms.getMobile());
        map.put("content", sms.getContent());
        map.put("fromUser", sms.getFromUser());
        map.put("toUser", sms.getToUser());
        return getRequestBody(map);
    }
    
	/**
	 * 包装请求基本为RequestBody对象
	 * @param sms
	 * @return
	 */
	private RequestBody getRequestMap(TemplateSms sms) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("mobile", sms.getMobile());
        map.put("templateId", sms.getTemplateId());
        map.put("templateCode", sms.getTemplateCode());
        map.put("fromUser", sms.getFromUser());
        map.put("toUser", sms.getToUser());
        if (sms.getParameters() != null && sms.getParameters().size() > 0) {
            for (Map.Entry<String, String> entry : sms.getParameters().entrySet()) {
                map.put("$" + entry.getKey(), entry.getValue());
            }
        }
        
        return getRequestBody(map);
    }
    
    /**
     * 包装基本参数和应用id并用key签名
     * @param map
     * @return
     */
    private RequestBody getRequestBody(Map<String, String> map) {
        map.put("version", "1.0");
        map.put("applicationId", appId);
        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
        map.put("sign", SmsUtils.sign(map, secretKey));
        FormEncodingBuilder build = new FormEncodingBuilder();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (entry.getValue() == null) {
                continue;
            }
            build.add(entry.getKey(), entry.getValue());
        }
        return build.build();
    }
    
	/** 随机生成6位纯数字的验证码 */
	public String createCode() {// 生成验证码
		int len = charset.length() - 1;
		String result = "";
		for (int i = 0; i < codelen; i++) {
			char[] arrs = charset.toCharArray();
			Random r = new Random();
			result += arrs[r.nextInt(len)];
		}
		return result;
	}
	
    /**
     * @desc 结果实体类
     * @author wjw
     * @time 2017年11月20日下午6:01:23
     */
    private static class RestResult {
        
        /** FIXME */
        private int state;
        
        /** FIXME */
        private String message;
        
        /**
         * @return the state
         */
        public int getState() {
            return state;
        }
        
        /**
         * @param state the state to set
         */
        public void setState(int state) {
            this.state = state;
        }
        
        /**
         * @return the message
         */
        public String getMessage() {
            return message;
        }
        
        /**
         * @param message the message to set
         */
        public void setMessage(String message) {
            this.message = message;
        }
        
        @Override
        public String toString() {
            return "RestResult [state=" + state + ", message=" + message + "]";
        }
        
    }
}
